package heap

import (
	"JVM/Jvmgo/GoToJVM/classfile"
	"strings"
)

/*
	方法区存放数据：
		1. 被虚拟机加载的类信息
		2. 常量
		3. 静态变量
		4. 即时编译器编译后的代码缓存等数据
*/

/*
关于descriptor的描述：
	A method descriptor contains zero or more parameter descriptors,
	representing the types of parameters that the method takes,
	and a return descriptor,
	representing the type of the value (if any) that the method returns.
*/
// 运行时常量池的类信息(由类文件复制过来)
type Class struct {
	magic             uint32
	minorVersion      uint16
	majorVersion      uint16
	accessFlags       uint16
	name              string
	superClassName    string
	interfaceNames    []string
	constantPool      *ConstantPool
	fields            []*Field
	methods           []*Method
	loader            *ClassLoader
	superClass        *Class
	interfaces        []*Class
	instanceSlotCount uint
	staticSlotCount   uint
	staticVars        Slots
	initStarted       bool    // todo 这目前只是对之前类加载机制进行补强，但是并未完善。用于标志类的 <clinit> 是否开始执行
	jClass            *Object // java中类也表现为普通对象
}

// 构造器
func newClass(cf *classfile.ClassFile) *Class {
	class := &Class{}
	class.magic = cf.Magic()
	class.majorVersion = cf.MajorVersion()
	class.accessFlags = cf.AccessFlags()
	class.name = cf.ClassName()
	class.superClassName = cf.SuperClassName()
	class.interfaceNames = cf.InterfaceNames()
	class.constantPool = newConstantPool(class, cf.ConstantPool())
	class.fields = newFields(class, cf.Fields())
	class.methods = newMethods(class, cf.Methods())
	return class
}

// 类中的accessFlags包含了8中类型的参数
func (self *Class) IsPublic() bool {
	return 0 != self.accessFlags&ACC_PUBLIC
}
func (self *Class) IsFinal() bool {
	return 0 != self.accessFlags&ACC_FINAL
}
func (self *Class) IsSuper() bool {
	return 0 != self.accessFlags&ACC_SUPER
}
func (self *Class) IsInterface() bool {
	return 0 != self.accessFlags&ACC_INTERFACE
}
func (self *Class) IsAbstract() bool {
	return 0 != self.accessFlags&ACC_ABSTRACT
}
func (self *Class) IsSynthetic() bool {
	return 0 != self.accessFlags&ACC_SYNTHETIC
}
func (self *Class) IsAnnotation() bool {
	return 0 != self.accessFlags&ACC_ANNOTATION
}
func (self *Class) IsEnum() bool {
	return 0 != self.accessFlags&ACC_ENUM
}
func (self *Class) IsModule() bool {
	return 0 != self.accessFlags&ACC_MODULE
}
func (self *Class) GetRefVar(fieldName, fieldDescriptor string) *Object {
	field := self.getField(fieldName, fieldDescriptor, true)
	return self.staticVars.GetRef(field.slotId)
}

// getters
func (self *Class) ConstantPool() *ConstantPool {
	return self.constantPool
}
func (self *Class) StaticVars() Slots {
	return self.staticVars
}
func (self *Class) SuperClass() *Class {
	return self.superClass
}
func (self *Class) Name() string {
	return self.name
}
func (self *Class) InitStarted() bool {
	return self.initStarted
}
func (self *Class) Loader() *ClassLoader {
	return self.loader
}
func (self *Class) JClass() *Object {
	return self.jClass
}
func (self *Class) SetRefVar(fieldName, fieldDescriptor string, ref *Object) {
	field := self.getField(fieldName, fieldDescriptor, true)
	self.staticVars.SetRef(field.slotId, ref)
}
func (self *Class) GetInstanceMethod(name, descriptor string) *Method {
	return self.getMethod(name, descriptor, false)
}
func (self *Class) getMethod(name, descriptor string, isStatic bool) *Method {
	for c := self; c != nil; c = c.superClass {
		for _, method := range c.methods {
			if method.IsStatic() == isStatic &&
				method.name == name &&
				method.descriptor == descriptor {
				return method
			}
		}
	}
	return nil
}

/*
获取包名，如：github.com/example/package1/ClassName
获取最后一个 '/' 前的字符串即包名
*/
func (self *Class) GetPackageName() string {
	if i := strings.LastIndex(self.name, "/"); i >= 0 {
		return self.name[:i]
	}
	return ""
}

/*
获取java类名
获取 java.lang.String 这种格式类名
*/
func (self *Class) JavaName() string {
	return strings.Replace(self.name, "/", ".", -1)
}

// jvms 5.4.4
// todo 双亲委派机制

/*
类a想访问类b，至少需要满足以下两个条件之一：
 1. 类b是public
 2. 类a和类b在同一个包下
*/
func (self *Class) isAccessibleTo(other *Class) bool {
	return self.IsPublic() ||
		self.getPackageName() == other.getPackageName()
}

// 获取运行时包名
func (self *Class) getPackageName() string {
	if i := strings.LastIndex(self.name, "/"); i >= 0 {
		return self.name[:i]
	}
	return ""
}

func (self *Class) GetMainMethod() *Method {
	return self.getStaticMethod("main", "([Ljava/lang/String;)V")
}

func (self *Class) getStaticMethod(name, descriptor string) *Method {
	for _, method := range self.methods {
		if method.IsStatic() &&
			method.name == name &&
			method.descriptor == descriptor {

			return method
		}
	}
	return nil
}
func (self *Class) NewObject() *Object {
	return newObject(self)
}

func (self *Class) StartInit() {
	self.initStarted = true
}

func (self *Class) GetClinitMethod() *Method {
	// 类加载方法为static，并且返回值为 void
	return self.getStaticMethod("<clinit>", "()V")
}

// 返回对应类的数组类
func (self *Class) ArrayClass() *Class {
	arrayClassName := getArrayClassName(self.name)
	return self.loader.LoadClass(arrayClassName)
}

// 寻找字段
func (self *Class) getField(name, descriptor string, isStatic bool) *Field {
	for c := self; c != nil; c = c.superClass {
		for _, field := range c.fields {
			if field.IsStatic() == isStatic &&
				field.name == name && field.descriptor == descriptor {
				return field
			}
		}
	}
	return nil
}

// 判断类
func (self *Class) isJlObject() bool {
	return self.name == "java/lang/Object"
}
func (self *Class) isJlCloneable() bool {
	return self.name == "java/lang/Cloneable"
}
func (self *Class) isJioSerializable() bool {
	return self.name == "java/io/Serializable"
}
func (self *Class) IsPrimitive() bool {
	_, ok := primitiveTypes[self.name]
	return ok
}
